package com.glela.firewall.service.impl;

import java.util.Date;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.glela.cache.redis.FirewallRedisUtil;
import com.glela.cache.redis.RedisKeys;
import com.glela.firewall.beans.FirewallLog;
import com.glela.firewall.service.FirewallService;
import com.glela.firewall.util.FirewallConfig;

/**
 * Created by liujie 
 */
@Service
public class FirewallServiceImpl implements FirewallService {

    private static Logger logger = LoggerFactory.getLogger(FirewallServiceImpl.class);

    private static Logger firewallLogger = LoggerFactory.getLogger("FirewallFileLog");

    @Autowired
    private FirewallRedisUtil redisUtil;

    @Override
    public boolean check(FirewallLog firewallLog) {
        if (StringUtils.isBlank(firewallLog.getIp()) || StringUtils.isBlank(firewallLog.getGuestId())) {
            logger.error("防火墙监测，ip或guestId为空，直接允许通过");
            return true;
        }

        if (FirewallConfig.isPropertiesNull()) {
            try {
                reloadFirewallFile();
            } catch (Exception e) {
                logger.error("加载防火墙配置文件出错，直接允许通过", e);
                return true;
            }
        }

        if (!FirewallConfig.getFirewallOpen()) {
            //防火墙总开关关闭，直接返回通过
            return true;
        }

        boolean result = true;
        if (!FirewallConfig.isWhiteIp(firewallLog.getIp()) &&
                FirewallConfig.getFirewallMonitorOpen() &&
                FirewallConfig.isBlackIp(firewallLog.getIp())) {
            // 不是白名单 且 防火墙监测开关开启 且 命中黑名单，则不允许通过
            result = false;
            firewallLog.setFilterType(4);
        } else if (!FirewallConfig.isWhiteIp(firewallLog.getIp()) &&
                FirewallConfig.getFirewallMonitorOpen() &&
                !FirewallConfig.isBlackIp(firewallLog.getIp())) {
            // 不是白名单 且 防火墙监测开关开启 且 不是黑名单
            String key = RedisKeys.FIREWALL_IP_DEV_PREFIX + convertIpToRedisKey(firewallLog.getIp()) + "_" + firewallLog.getGuestId();
            boolean keyExist = redisUtil.exists(key);
            if (keyExist) {
                // 老设备访问，更新过期时间，允许通过
                redisUtil.expire(key, FirewallConfig.getFirewallMonitorHour() * 60 * 60);
            } else {
                // 新设备访问
                Set<String> devs = redisUtil.getKeys(RedisKeys.FIREWALL_IP_DEV_PREFIX + convertIpToRedisKey(firewallLog.getIp()) + "*");
                if (devs.size() < FirewallConfig.getFirewallDevMaxCount()) {
                    //未超过最大设备数
                    redisUtil.set(key, "1", FirewallConfig.getFirewallMonitorHour() * 60 * 60);
                } else {
                    //超过最大设备数，不允许通过
                    result = false;
                    firewallLog.setFilterType(3);
                }
            }
        }

        if (result && FirewallConfig.isWhiteIp(firewallLog.getIp())) {
            //白名单允许通过
            firewallLog.setFilterType(2);
        } else if (result &&
                !FirewallConfig.isWhiteIp(firewallLog.getIp()) &&
                !FirewallConfig.getFirewallMonitorOpen()) {
            //未验证允许通过
            firewallLog.setFilterType(5);
        } else if (result) {
            //验证允许通过
            firewallLog.setFilterType(1);
        }

        if (FirewallConfig.getFirewallPersistOpen()) {
            firewallLog.setTime(new Date());
            firewallLogger.info(firewallLog.toString());
//            redisUtil.setObjectToDBIndex(RedisKeys.FIREWALL_LOG_IP_DEV_TIME + convertIpToRedisKey(firewallLog.getIp()) + "_" + firewallLog.getGuestId() + "_" + firewallLog.getTime().getTime(), firewallLog, 1);
        }

        return result;
    }

    @Override
    public void reloadFirewallFile() throws Exception {
        FirewallConfig.loadFirewallConfigFile();
    }

    private String convertIpToRedisKey(String ip) {
        return ip.replace(".", "-");
    }
}
